package main

import (
	"io/ioutil"
	"log"
	"os"
	"syscall"
	"unsafe"
)

/*type DOC_INFO_1 struct {
	pDocName    []byte
	pOutputFile []byte
	pDatatype   []byte
}*/
type DOC_INFO_1 struct {
	DocName    *uint16
	OutputFile *uint16
	Datatype   *uint16
}

var (
	dll               = syscall.MustLoadDLL("winspool.drv")
	getDefaultPrinter = dll.MustFindProc("GetDefaultPrinterW")
	openPrinter       = dll.MustFindProc("OpenPrinterW")
	startDocPrinter   = dll.MustFindProc("StartDocPrinterW")
	startPagePrinter  = dll.MustFindProc("StartPagePrinter")
	writePrinter      = dll.MustFindProc("WritePrinter")
	endPagePrinter    = dll.MustFindProc("EndPagePrinter")
	endDocPrinter     = dll.MustFindProc("EndDocPrinter")
	closePrinter      = dll.MustFindProc("ClosePrinter")
)

func main() {

	printerName, printerName16 := getDefaultPrinterName()
	log.Println(printerName)
	printerHandle := openPrinterFunc(printerName, printerName16)
	log.Println(printerHandle)
	log.Println("---------------")
	startPrinter(printerHandle)
	//
	startPagePrinter.Call(printerHandle)

	writePrinterFunc("file/1.html", printerHandle)

	endPagePrinter.Call(printerHandle)
	endDocPrinter.Call(printerHandle)
	closePrinter.Call(printerHandle)
	os.Exit(2)
}

func writePrinterFunc(filename string, printerHandle uintptr) {

	fileContents, _ := ioutil.ReadFile(filename)
	log.Println("------aaaaa--------")
	//log.Println(string(fileContents))
	//fileContents = []byte(fileContents)
	fileContents2 := []byte(fileContents)
	//log.Println(fileContents2)
	var contentLen uintptr = uintptr(len(fileContents))
	var writtenLen int
	/*writePrinter.Call(printerHandle,
	uintptr(unsafe.Pointer(&fileContents[0])), contentLen,
	uintptr(unsafe.Pointer(&writtenLen)))*/
	r1, _, e1 := syscall.Syscall6(writePrinter.Addr(),
		4, printerHandle, uintptr(unsafe.Pointer(&fileContents2[0])),
		contentLen, uintptr(unsafe.Pointer(&writtenLen)), 0, 0)
	if r1 == 0 {
		if e1 != 0 {
			err := error(e1)
			log.Println(err)
		} else {
			err := syscall.EINVAL
			log.Println(err)
		}
	}
	log.Println(r1)
	log.Println(e1)

}

func startPrinter(printerHandle uintptr) {

	/*di := DOC_INFO_1{[]byte(""), nil, []byte("TEXT")}
	startDocPrinter.Call(printerHandle, 1, uintptr(unsafe.Pointer(&di)))*/
	d := DOC_INFO_1{
		DocName: &(syscall.StringToUTF16("print"))[0],
		//OutputFile: &(syscall.StringToUTF16("f://print.txt"))[0],
		OutputFile: nil,
		Datatype:   &(syscall.StringToUTF16("RAW"))[0],
	}
	r1, _, e1 := syscall.Syscall(startDocPrinter.Addr(), 3, uintptr(printerHandle),
		uintptr(1), uintptr(unsafe.Pointer(&d)))
	if r1 == 0 {
		if e1 != 0 {
			err := error(e1)
			log.Println(err)
		} else {
			err := syscall.EINVAL
			log.Println(err)
		}
	}
	log.Println(r1)
	log.Println(e1)
	return
}

func openPrinterFunc(printerName string, printerName16 []uint16) uintptr {

	var printerHandle uintptr
	openPrinter.Call(uintptr(unsafe.Pointer(&printerName16[0])),
		uintptr(unsafe.Pointer(&printerHandle)), 0)
	return (printerHandle)

}

func getDefaultPrinterName() (string, []uint16) {

	var pn [256]uint16
	plen := len(pn)
	getDefaultPrinter.Call(uintptr(unsafe.Pointer(&pn)),
		uintptr(unsafe.Pointer(&plen)))
	printerName := syscall.UTF16ToString(pn[:])
	return printerName, syscall.StringToUTF16(printerName)

}
